package cn.wen233.srpc.core.holder;

import cn.wen233.basic.model.Instance;
import cn.wen233.basic.model.Service;
import cn.wen233.srpc.basic.model.ServerConfig;
import cn.wen233.srpc.basic.model.ServerInstance;
import cn.wen233.srpc.basic.rollback.DefaultRollbackFactory;
import cn.wen233.srpc.core.service.factory.ReferenceProxyFactory;
import cn.wen233.srpc.core.spring.client.ReferencePostProcessor;
import cn.wen233.srpc.core.sunglow.http.Sunglow;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 客户端 代理对象持有器
 *
 * @author wenei
 * @date 2021-12-27 22:12
 */
@Slf4j
public class ClientServiceHolder {

    private static final Map<Class<?>, Object> proxyMap = new HashMap<>();

    private static ScheduledThreadPoolExecutor threadPool = new ScheduledThreadPoolExecutor(1);

    static {
        // 定时更新服务信息 采用定时拉取的方式
        threadPool.scheduleAtFixedRate(() -> {
            for (Map.Entry<Class<?>, Object> classObjectEntry : proxyMap.entrySet()) {
                Class<?> serviceClass = classObjectEntry.getKey();
                Service service = Sunglow.getService(serviceClass.getName());
                if (service == null) {
                    continue;
                }
                List<Instance> allInstance = Sunglow.getAllInstance(service.getId());
                ServerConfig config = new ServerConfig();
                config.setServiceName(service.getName());
                config.setInstances(allInstance.stream().map(instance -> {
                    ServerInstance serverInstance = new ServerInstance();
                    serverInstance.setHost(instance.getIp());
                    serverInstance.setPort(instance.getPort());
                    return serverInstance;
                }).collect(Collectors.toList()));
                log.debug("serviceName={}使用Sunglow服务中心 serviceConfig={}", service.getName(), config);
                putProxy(
                        serviceClass,
                        () -> ReferenceProxyFactory.getProxyService(serviceClass, config, DefaultRollbackFactory.class)
                );
                // 替换spring容器中的field
                ReferencePostProcessor.injectProxy(serviceClass, getProxy(serviceClass));
            }
        }, 5, 5, TimeUnit.SECONDS);
    }

    public static <T> T getProxy(Class<T> tClass) {
        return (T) proxyMap.get(tClass);
    }

    public static void putProxy(Class<?> tClass, Supplier<?> supplier) {
        proxyMap.put(tClass, supplier.get());
    }
}
